package com.hyt.it.ogt.kq.service.gov.service.impl;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hyt.core.base.BaseServiceImpl;
import com.hyt.core.util.DateUtils;
import com.hyt.core.util.UUIDUtils;
import com.hyt.it.ogt.kq.common.config.ConfigManager;
import com.hyt.it.ogt.kq.common.config.exception.KqException;
import com.hyt.it.ogt.kq.common.gov.constant.ResponseCode;
import com.hyt.it.ogt.kq.common.gov.constant.StringCodeEnum;
import com.hyt.it.ogt.kq.common.gov.constant.examsys.TypeEnum;
import com.hyt.it.ogt.kq.common.gov.enums.FileTypeEnum;
import com.hyt.it.ogt.kq.common.gov.enums.TaskConfigCodeEnum;
import com.hyt.it.ogt.kq.common.gov.enums.TaskConfigTypeEnum;
import com.hyt.it.ogt.kq.common.gov.utils.DateTimeUtil;
import com.hyt.it.ogt.kq.common.gov.utils.FileUtil;
import com.hyt.it.ogt.kq.common.gov.utils.XmlUtil;
import com.hyt.it.ogt.kq.common.gov.utils.ZipUtil;
import com.hyt.it.ogt.kq.service.gov.mapper.AgreementMapper;
import com.hyt.it.ogt.kq.service.gov.mapper.BaseDataPackageMapper;
import com.hyt.it.ogt.kq.service.gov.mapper.ExamPackageMapper;
import com.hyt.it.ogt.kq.service.gov.model.entity.Agreement;
import com.hyt.it.ogt.kq.service.gov.model.entity.BaseDataPackage;
import com.hyt.it.ogt.kq.service.gov.model.entity.BreakRuleBehavior;
import com.hyt.it.ogt.kq.service.gov.model.entity.BreakRuleScheme;
import com.hyt.it.ogt.kq.service.gov.model.entity.ExamPackage;
import com.hyt.it.ogt.kq.service.gov.model.entity.SysFile;
import com.hyt.it.ogt.kq.service.gov.model.entity.Task;
import com.hyt.it.ogt.kq.service.gov.model.entity.TaskConfig;
import com.hyt.it.ogt.kq.service.gov.model.vo.basepackage.BaseDataPackageVO;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceBreakRule;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceBreakRuleFileInfo;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceBreakRuleInfo;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceBreakRuleScheme;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceBreakRuleSchemeContent;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceExamConferFileInfo;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceExamInfo;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceFileList;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.gce.GceLanguageInfo;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.obt.ExamConferInfo;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.obt.ExamInfo;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.obt.ExamViolation;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.obt.ExamWj;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.obt.ExamWjCl;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.obt.ExamWjClConn;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.obt.FileList;
import com.hyt.it.ogt.kq.service.gov.model.xml.basedatapackage.obt.ViolationManage;
import com.hyt.it.ogt.kq.service.gov.service.IAgreementService;
import com.hyt.it.ogt.kq.service.gov.service.IBreakRuleBehaviorService;
import com.hyt.it.ogt.kq.service.gov.service.IBreakRuleSchemeService;
import com.hyt.it.ogt.kq.service.gov.service.IExamPackageService;
import com.hyt.it.ogt.kq.service.gov.service.ISysFileService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskConfigService;
import com.hyt.it.ogt.kq.service.gov.service.ITaskService;
import com.hyt.it.ogt.kq.service.gov.service.obs.CloudObsService;

import cn.hutool.core.collection.ListUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.lingala.zip4j.exception.ZipException;

/**
 * <p>
 * 文件数据包表 服务实现类
 * </p>
 *
 * @author huangyh
 * @since 2021-03-08
 */
@Slf4j
@Service
public class ExamPackageServiceImpl extends BaseServiceImpl<ExamPackageMapper, ExamPackage> implements IExamPackageService {

    private static final String BASE_DATA_PACKAGE_SUFFIX_NAME = "基础包";

    private static final String BASE_DATA_PACKAGE_TEMP_DIR = "files";

    private static final String BASE_DATA_PACKAGE_EXTENSION = ".bdp";

    private static final String BASE_DATA_PACKAGE_VIOLATION_MANAGE = "ViolationManage.xml";

    private static final String BASE_DATA_PACKAGE_BREAK_RULE = "违纪处理办法.zip";

    private static final String BASE_DATA_PACKAGE_FILE_LIST = "FileList.xml";

    private static final String FORMAT_DATE_PATTERN = "yyyyMMddHHmmssSSS";

    public static final String CLOUD_PATH_BASE_DATA_PACKAGE = "/baseData/";

    @Resource
    private ITaskService iTaskService;

    @Resource
    private IExamPackageService iExamPackageService;

    @Resource
    private IBreakRuleSchemeService iBreakRuleSchemeService;

    @Resource
    private IBreakRuleBehaviorService iBreakRuleBehaviorService;

    @Resource
    private ConfigManager configManager;

    @Resource
    private AgreementMapper agreementMapper;

    @Resource
    private ITaskConfigService iTaskConfigService;

    @Resource
    private CloudObsService cloudObsService;

    @Resource
    private BaseDataPackageMapper baseDataPackageMapper;

    @Resource
    private ISysFileService iSysFileService;

    @Resource
    private IAgreementService iAgreementService;

    @Override
    public boolean add(ExamPackage examPackage) {
        return save(examPackage);
    }

    @Override
    public List<ExamPackage> listByTaskCode(String taskCode) {
        return iExamPackageService.listByTaskCode(taskCode);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void generateBaseDataPackage(String taskId) {
        // 校验任务数据锁定状态(后续版本考虑优化为从缓存中获取状态)
        iTaskService.isLockDataThrowException(taskId);
        Task task = iTaskService.getById(taskId);
        // 生成前校验
        this.check(task);
        //获取考试任务对应的考试系统类型
        Optional<String> optional = iTaskConfigService.getExamSystemTypeByTaskId(taskId);
        //根据考试系统类型区分生成基础包的数据格式，生成基础包
        optional.ifPresent(type -> {
            switch (TypeEnum.getType(type)) {
                //生成OBT基础包
                case OBT:
                    this.generateObtBaseDataPackage(taskId, task);
                    break;
                //生成GCE基础包
                case GCE:
                    this.generateGceBaseDataPackage(task);
                    break;
            }
        });
    }

    /**
     * 生成OBT考试系统基础包
     * @param taskId 考试任务id
     * @param task 考试任务
     */
    @SneakyThrows
    private void generateObtBaseDataPackage(String taskId, Task task) {
        // 定义生成基础包的跟路径，最终包生成放在这个目录下
        String rootDir = StringUtils.join(configManager.getBaseDataPackageTemp(), UUIDUtils.newSortUUID(),
                File.separator);
        // 定义包内容的文件路径
        String filesDir = StringUtils.join(rootDir, BASE_DATA_PACKAGE_TEMP_DIR, File.separator);
        new File(filesDir).mkdirs();
        File agreementFile = this.createAgreementFile(taskId, filesDir);
        File breakRuleFile = this.createBreakRuleFile(taskId, filesDir);
        File fileList = this.createFileListFile(task, agreementFile, breakRuleFile, filesDir);
        File zip = this.createTotalPackage(task, rootDir, agreementFile, breakRuleFile, fileList);
        String path = StringUtils.join(configManager.getCloudRootPath(), task.getCode(),
                CLOUD_PATH_BASE_DATA_PACKAGE, DateTimeUtil.getNowString(), "/", zip.getName());
        //基础包上传云存储
        String url = cloudObsService.updateFile(path, zip);
        this.save2Db(taskId, url, path, zip.getName(), null);
    }

    @SneakyThrows
    private void generateGceBaseDataPackage(Task task) {
        //存放所有文件的临时目录
        File tempDirectory = null;
        try {
            //获取时间戳，用于记录基础包版本
            String timestamp = DateTimeUtil.getNowString();
            //创建存放所有文件的临时目录
            tempDirectory = Files.createTempDirectory(BASE_DATA_PACKAGE_TEMP_DIR +
                    "_" + UUIDUtils.newSortUUID()).toFile();
            //生成考试协议zip文件
            File examConferZip = this.createGceExamConferZipFile(task, tempDirectory);
            //生成违纪信息zip文件
            File breakRuleZip = this.createGceBreakRuleZipFile(task, tempDirectory);
            //生成基础包文件信息xml文件
            File fileListXml = this.createGceFileListXml(timestamp, task, tempDirectory, examConferZip, breakRuleZip);
            //将所有已生成的文件打包为基础包文件
            ArrayList<File> toBePackedFileList = ListUtil.toList(examConferZip, breakRuleZip, fileListXml);
            File baseDataPackage = this.wrapGceBaseDataPackage(task, tempDirectory, toBePackedFileList);
            //将基础包文件上传至华为云OBS
            String path = StringUtils.join(configManager.getCloudRootPath(), task.getCode(),
                    CLOUD_PATH_BASE_DATA_PACKAGE, timestamp, "/", baseDataPackage.getName());
            String url = cloudObsService.updateFile(path, baseDataPackage);
            //基础包信息保存至数据库
            this.save2Db(task.getId(), url, path, baseDataPackage.getName(), timestamp);
        } finally {
            //删除临时目录
            if (tempDirectory != null) {
                FileUtils.deleteDirectory(tempDirectory);
            }
        }
    }

    private File createGceExamConferZipFile(Task task, File tempDirectory) throws Exception {
        Agreement agreement = iAgreementService.lambdaQuery()
                .eq(Agreement::getTaskId, task.getId())
                .last("LIMIT 1")
                .oneOpt()
                .orElseThrow(() -> new KqException(ResponseCode.BASE_DATA_PACKAGE_AGREEMENT_NOT_EXIST.getCode(),
                        ResponseCode.BASE_DATA_PACKAGE_AGREEMENT_NOT_EXIST.getMsg()));
        SysFile sysFile = iSysFileService.getById(agreement.getFileId());
        if (ObjectUtils.isEmpty(sysFile)) {
            throw new KqException(ResponseCode.BASE_DATA_PACKAGE_AGREEMENT_NOT_EXIST.getCode(),
                    ResponseCode.BASE_DATA_PACKAGE_AGREEMENT_NOT_EXIST.getMsg());
        }
        File file = new File(tempDirectory, sysFile.getName());
        FileUtil.writeFile(cloudObsService.downFile(sysFile.getPath()), file);
        return file;
    }

    private File createGceBreakRuleZipFile(Task task, File tempDirectory) throws Exception {
        //获取违纪行为数据
        List<BreakRuleBehavior> breakRuleBehaviorList = iBreakRuleBehaviorService.lambdaQuery()
                .eq(BreakRuleBehavior::getTaskId, task.getId())
                .eq(BreakRuleBehavior::getDelFlag, false)
                .orderByAsc(BreakRuleBehavior::getSort)
                .list();
        if (CollectionUtils.isEmpty(breakRuleBehaviorList)) {
            throw new KqException(ResponseCode.GENERATE_BASE_DATA_PACKAGE_BREAK_RULE_BEHAVIOR_NOT_ADD.getCode(),
                    ResponseCode.GENERATE_BASE_DATA_PACKAGE_BREAK_RULE_BEHAVIOR_NOT_ADD.getMsg());
        }
        //获取违纪处理数据
        List<BreakRuleScheme> breakRuleSchemeList = iBreakRuleSchemeService.lambdaQuery()
                .eq(BreakRuleScheme::getTaskId, task.getId())
                .eq(BreakRuleScheme::getDelFlag, false)
                .orderByAsc(BreakRuleScheme::getSort)
                .list();
        if (CollectionUtils.isEmpty(breakRuleSchemeList)) {
            throw new KqException(ResponseCode.GENERATE_BASE_DATA_PACKAGE_BREAK_RULE_SCHEME_NOT_ADD.getCode(),
                    ResponseCode.GENERATE_BASE_DATA_PACKAGE_BREAK_RULE_SCHEME_NOT_ADD.getMsg());
        }
        //组装违纪行为数据
        List<GceBreakRule> gceBreakRuleList = breakRuleBehaviorList.stream().map(breakRuleBehavior -> {
            GceBreakRule gceBreakRule = new GceBreakRule();
            gceBreakRule.setBreakRuleCode(breakRuleBehavior.getCode())
                    .setBreakRuleContent(breakRuleBehavior.getContent());
            return gceBreakRule;
        }).collect(Collectors.toList());
        //组装违纪处理数据
        List<GceBreakRuleScheme> gceBreakRuleSchemeList = breakRuleSchemeList.stream().map(breakRuleScheme -> {
            GceBreakRuleScheme gceBreakRuleScheme = new GceBreakRuleScheme();
            gceBreakRuleScheme.setSchemeCode(breakRuleScheme.getCode())
                    .setSchemeContent(breakRuleScheme.getContent())
                    .setBanYears(String.valueOf(breakRuleScheme.getBanYears()))
                    .setForcedEnd(breakRuleScheme.getForcedEnd() ?
                            StringCodeEnum.FORCED_END_TRUE.getCode() : StringCodeEnum.FORCED_END_FALSE.getCode());
            return gceBreakRuleScheme;
        }).collect(Collectors.toList());
        //组装违纪行为与违纪处理对应关系数据
        List<GceBreakRuleSchemeContent> gceBreakRuleSchemeContentList = breakRuleBehaviorList.stream().map(breakRuleBehavior -> {
            GceBreakRuleSchemeContent gceBreakRuleSchemeContent = new GceBreakRuleSchemeContent();
            gceBreakRuleSchemeContent.setBreakRuleCode(breakRuleBehavior.getCode());
            BreakRuleScheme scheme = breakRuleSchemeList.stream()
                    .filter(breakRuleScheme -> breakRuleBehavior.getSchemeId().equals(breakRuleScheme.getId()))
                    .findFirst()
                    .orElseThrow(() -> new KqException(ResponseCode.ERROR_GENERATE_BASE_DATA_PACKAGE.getCode(),
                            "违纪行为 '" + breakRuleBehavior.getContent() + "'找不到对应的违纪行为处理方案"));
            gceBreakRuleSchemeContent.setSchemeCode(scheme.getCode());
            return gceBreakRuleSchemeContent;
        }).collect(Collectors.toList());
        //组装违纪信息数据
        GceBreakRuleInfo gceBreakRuleInfo = new GceBreakRuleInfo();
        gceBreakRuleInfo.setBreakRuleList(gceBreakRuleList)
                .setBreakRuleSchemeList(gceBreakRuleSchemeList)
                .setBreakRuleSchemeContentList(gceBreakRuleSchemeContentList);
        //生成违纪信息XML文件
        File breakRuleXmlFile = new File(tempDirectory, BASE_DATA_PACKAGE_VIOLATION_MANAGE);
        XmlUtil.toXmlFile(gceBreakRuleInfo, breakRuleXmlFile.getAbsolutePath());
        //生成违纪信息zip包文件
        File breakRuleZipFile = new File(tempDirectory, BASE_DATA_PACKAGE_BREAK_RULE);
        ArrayList<String> fileList = new ArrayList<>();
        fileList.add(breakRuleXmlFile.getAbsolutePath());
        ZipUtil.zipFiles(fileList, breakRuleZipFile.getAbsolutePath());
        return breakRuleZipFile;
    }

    private File createGceFileListXml(String timestamp, Task task, File tempDirectory,
                                      File examConferZip, File breakRuleZip) {
        //获取考试任务下的考试系统配置
        List<TaskConfig> configList = iTaskConfigService.getByTaskId(task.getId());
        //获取考试系统版本号配置
        String examSystemVersion = configList.stream().filter(l ->
                TaskConfigTypeEnum.EXAM_CONFIG.getCode().equalsIgnoreCase(l.getType()) &&
                        TaskConfigCodeEnum.EXAM_VERSION.getCode().equalsIgnoreCase(l.getCode()))
                .findFirst()
                .map(TaskConfig::getValue)
                .orElseThrow(() -> new KqException(ResponseCode.ERROR_GENERATE_BASE_DATA_PACKAGE.getCode(),
                        "考试任务'" + task.getCode() + "'的考试系统版本号配置不存在"));
        //获取考试系统脚本版本号配置
        String examSystemScriptVersion = configList.stream().filter(l ->
                TaskConfigTypeEnum.EXAM_CLIENT.getCode().equalsIgnoreCase(l.getType()) &&
                        TaskConfigCodeEnum.SCRIPT_VERSION.getCode().equalsIgnoreCase(l.getCode()))
                .findFirst()
                .map(TaskConfig::getValue)
                .orElseThrow(() -> new KqException(ResponseCode.ERROR_GENERATE_BASE_DATA_PACKAGE.getCode(),
                        "考试任务'" + task.getCode() + "'的考试系统脚本版本号配置不存在"));
        //组装基础包文件信息列表数据
        GceFileList gceFileList = new GceFileList();
        gceFileList.setExamSystemVersion(examSystemVersion)
                .setExamSystemScriptVersion(examSystemScriptVersion)
                .setTimestamp(timestamp);
        //组装考试信息数据
        GceExamInfo gceExamInfo = new GceExamInfo();
        gceExamInfo.setTaskCode(task.getCode())
                .setExamType(String.valueOf(task.getType()));
        gceFileList.setGceExamInfo(gceExamInfo);
        //组装考试协议文件信息数据
        Optional.of(examConferZip).map(examConfer -> {
            List<GceExamConferFileInfo> gceExamConferFileInfoList = new ArrayList<>();
            GceExamConferFileInfo gceExamConferFileInfo = new GceExamConferFileInfo();
            gceExamConferFileInfo.setName(examConfer.getName())
                    .setSize(String.valueOf(examConfer.length()))
                    .setMd5(FileUtil.getFileMd5(examConfer));
            gceExamConferFileInfoList.add(gceExamConferFileInfo);
            return gceExamConferFileInfoList;
        }).ifPresent(gceFileList::setGceExamConferFileInfoList);
        //组装违纪文件信息数据
        Optional.of(breakRuleZip).map(breakRule -> {
            List<GceBreakRuleFileInfo> gceBreakRuleFileInfoList = new ArrayList<>();
            GceBreakRuleFileInfo gceBreakRuleFileInfo = new GceBreakRuleFileInfo();
            gceBreakRuleFileInfo.setName(breakRule.getName())
                    .setSize(String.valueOf(breakRule.length()))
                    .setMd5(FileUtil.getFileMd5(breakRule));
            gceBreakRuleFileInfoList.add(gceBreakRuleFileInfo);
            return gceBreakRuleFileInfoList;
        }).ifPresent(gceFileList::setGceBreakRuleFileInfoList);
        //组装语言信息数据
        List<GceLanguageInfo> gceLanguageInfoList = new ArrayList<>();
        GceLanguageInfo gceLanguageInfo = new GceLanguageInfo();
        // 不知道做什么用的，暂时写死为"1"
        gceLanguageInfo.setLanguageId("1");
        gceFileList.setGceLanguageInfoList(gceLanguageInfoList);
        //生成xml文件
        File fileListXml = new File(tempDirectory, BASE_DATA_PACKAGE_FILE_LIST);
        XmlUtil.toXmlFile(gceFileList, fileListXml.getAbsolutePath(), true);
        return fileListXml;
    }

    private File wrapGceBaseDataPackage(Task task, File tempDirectory,
                                        ArrayList<File> toBePackedFileList) throws Exception {
        //生成基础包文件名
        String baseDataPackageName = StringUtils.join(task.getName(), BASE_DATA_PACKAGE_SUFFIX_NAME, "_",
                task.getCode(), BASE_DATA_PACKAGE_EXTENSION);
        File baseDataPackage = new File(tempDirectory, baseDataPackageName);
        ZipUtil.zipWithPassword(toBePackedFileList, baseDataPackage.getAbsolutePath(), configManager.getGceBaseDataPackagePassword());
        return baseDataPackage;
    }

    /**
     * 保存数据库
     * @param taskId
     * @param url
     * @param path
     * @param name
     */
    private void save2Db(String taskId, String url, String path, String name, String version) {
        SysFile sysFile = new SysFile();
        sysFile.setName(name).setPath(path).setUrl(url).setType(FileTypeEnum.FILE_BASIC_PACKAGE.getName());
        iSysFileService.save(sysFile);

        BaseDataPackage baseDataPackage = new BaseDataPackage();
        baseDataPackage.setFileId(sysFile.getId());
        baseDataPackage.setUpdateDate(LocalDateTime.now());
        baseDataPackage.setVersion(version);

        LambdaQueryWrapper<BaseDataPackage> query = Wrappers.<BaseDataPackage>lambdaQuery()
                .eq(BaseDataPackage::getTaskId, taskId);
        boolean flag = false;
        try {
            if (baseDataPackageMapper.selectCount(query) == 0) {
                baseDataPackage.setTaskId(taskId);
                baseDataPackage.setCreateDate(LocalDateTime.now());
                baseDataPackageMapper.insert(baseDataPackage);
            } else {
                flag = true;
            }
        } catch (DuplicateKeyException e) {
            flag = true;
        }

        if (flag) {
            baseDataPackageMapper.update(baseDataPackage, query);
        }
    }

    /**
     * 生成基础包
     *
     * @param task
     * @param tempDir
     * @param agreementFile
     * @param breakRuleFile
     * @param fileList
     * @throws ZipException
     */
    private File createTotalPackage(Task task, String tempDir, File agreementFile, File breakRuleFile,
                                    File fileList) throws ZipException {
        // 最终包包含3个文件
        String zipFileName = StringUtils.join(task.getName(), BASE_DATA_PACKAGE_SUFFIX_NAME, "_",
                task.getCode(), BASE_DATA_PACKAGE_EXTENSION);
        String zipFilePath = tempDir + zipFileName;
        File zipFile = new File(zipFilePath);
        zipFile.getParentFile().mkdirs();
        zipFile.deleteOnExit();
        ArrayList<File> files = new ArrayList<>();
        files.add(fileList);
        files.add(breakRuleFile);
        files.add(agreementFile);
        ZipUtil.zipWithPassword(files, zipFile.getAbsolutePath(), configManager.getObtBaseDataPackagePassword());
        return zipFile;
    }

    /**
     * 生成考试协议包
     *
     * @param taskId
     * @param tempDir
     * @return
     * @throws IOException
     */
    private File createAgreementFile(String taskId, String tempDir) throws IOException {
        Agreement agreement = agreementMapper.selectOne(Wrappers.<Agreement>lambdaQuery()
                .eq(Agreement::getTaskId, taskId).last("limit 1"));
        if (agreement == null) {
            throw new KqException(ResponseCode.BASE_DATA_PACKAGE_AGREEMENT_NOT_EXIST.getCode(),
                    ResponseCode.BASE_DATA_PACKAGE_AGREEMENT_NOT_EXIST.getMsg());
        }
        SysFile sysFile = iSysFileService.getById(agreement.getFileId());
        if (sysFile == null) {
            throw new KqException(ResponseCode.BASE_DATA_PACKAGE_AGREEMENT_NOT_EXIST.getCode(),
                    ResponseCode.BASE_DATA_PACKAGE_AGREEMENT_NOT_EXIST.getMsg());
        }
        File file = new File(tempDir, sysFile.getName());
        FileUtil.writeFile(cloudObsService.downFile(sysFile.getPath()), file);
        return file;
    }

    /**
     * 生成文件清单文件
     *
     * @param task
     * @param agreementFile
     * @param breakRuleFile
     * @param tempDir
     * @return
     */
    private File createFileListFile(Task task, File agreementFile, File breakRuleFile, String tempDir) {
        List<TaskConfig> configList = iTaskConfigService.getByTaskId(task.getId());
        // 获取考试系统脚本版本号
        Optional<TaskConfig> scriptVerConfig = configList.stream().filter(l ->
                TaskConfigTypeEnum.EXAM_CLIENT.getCode().equalsIgnoreCase(l.getType()) &&
                        TaskConfigCodeEnum.SCRIPT_VERSION.getCode().equalsIgnoreCase(l.getCode()))
                .findFirst();
        // 获取考试系统版本号
        Optional<TaskConfig> sysVerConfig = configList.stream().filter(l ->
                TaskConfigTypeEnum.EXAM_CONFIG.getCode().equalsIgnoreCase(l.getType()) &&
                        TaskConfigCodeEnum.EXAM_VERSION.getCode().equalsIgnoreCase(l.getCode()))
                .findFirst();
        // 文件数据组装
        FileList fileData = new FileList();
        fileData.getExamConferList().add(new ExamConferInfo());
        fileData.getExamViolationList().add(new ExamViolation());
        fileData.getExamConferList().get(0).setFileName(agreementFile.getName());
        fileData.getExamConferList().get(0).setFileMd5(FileUtil.getFileMd5(agreementFile));
        fileData.getExamConferList().get(0).setFileSize(String.valueOf(agreementFile.length()));
        fileData.getExamViolationList().get(0).setFileName(breakRuleFile.getName());
        fileData.getExamViolationList().get(0).setFileMd5(FileUtil.getFileMd5(breakRuleFile));
        fileData.getExamViolationList().get(0).setFileSize(String.valueOf(breakRuleFile.length()));
        fileData.setVer(DateUtils.formatDatetime(new Date(), FORMAT_DATE_PATTERN));
        fileData.setScriptVer(scriptVerConfig.isPresent() ? scriptVerConfig.get().getValue() : "");
        fileData.setSysVer(sysVerConfig.isPresent() ? sysVerConfig.get().getValue() : "");

        ExamInfo examInfo = new ExamInfo();
        examInfo.setExamCode(task.getCode());
        examInfo.setProjectType(task.getType() + "");
        fileData.setExamInfo(examInfo);

        // 生成文件
        File xmlFile = new File(tempDir + BASE_DATA_PACKAGE_FILE_LIST);
        xmlFile.getParentFile().mkdirs();
        XmlUtil.toXmlFile(fileData, xmlFile.getAbsolutePath(), true);
        return xmlFile;
    }

    /**
     * 生成违纪包
     *
     * @param taskId
     * @param tempDir
     * @return
     * @throws ZipException
     */
    private File createBreakRuleFile(String taskId, String tempDir) throws ZipException {
        List<BreakRuleScheme> schemeList = iBreakRuleSchemeService.list(Wrappers.<BreakRuleScheme>lambdaQuery()
                .eq(BreakRuleScheme::getTaskId, taskId).eq(BreakRuleScheme::getDelFlag, false));
        if (CollectionUtils.isEmpty(schemeList)) {
            throw new KqException(ResponseCode.GENERATE_BASE_DATA_PACKAGE_BREAK_RULE_SCHEME_NOT_ADD.getCode(),
                    ResponseCode.GENERATE_BASE_DATA_PACKAGE_BREAK_RULE_SCHEME_NOT_ADD.getMsg());
        }
        List<BreakRuleBehavior> behaviorList = iBreakRuleBehaviorService.list(Wrappers.<BreakRuleBehavior>lambdaQuery()
                .eq(BreakRuleBehavior::getTaskId, taskId).eq(BreakRuleBehavior::getDelFlag, false));
        if (CollectionUtils.isEmpty(behaviorList)) {
            throw new KqException(ResponseCode.GENERATE_BASE_DATA_PACKAGE_BREAK_RULE_BEHAVIOR_NOT_ADD.getCode(),
                    ResponseCode.GENERATE_BASE_DATA_PACKAGE_BREAK_RULE_BEHAVIOR_NOT_ADD.getMsg());
        }
        // 存放违纪处理表id和code对应关系
        Map<String, String> schemeCodeMap = new HashMap<>(16);
        ViolationManage violationManage = new ViolationManage();
        // 组装违纪处理数据
        for (BreakRuleScheme scheme : schemeList) {
            ExamWjCl examWjCl = new ExamWjCl();
            examWjCl.setClbf(scheme.getContent());
            examWjCl.setCldm(scheme.getCode());
            examWjCl.setEndExam(scheme.getForcedEnd() == true ? "1" : "0");
            examWjCl.setTknx(scheme.getBanYears().toString());
            violationManage.getExamWjclList().add(examWjCl);
            schemeCodeMap.put(scheme.getId(), scheme.getCode());
        }
        // 组装违纪处理办法
        for (BreakRuleBehavior behavior : behaviorList) {
            ExamWj examWj = new ExamWj();
            examWj.setWjdm(behavior.getCode());
            examWj.setWjms(behavior.getContent());
            violationManage.getExamWjList().add(examWj);
            ExamWjClConn examWjClConn = new ExamWjClConn();
            examWjClConn.setWjdm(behavior.getCode());
            examWjClConn.setCldm(schemeCodeMap.get(behavior.getSchemeId()));
            violationManage.getExamWjClConnList().add(examWjClConn);
        }

        String violationManagePath = tempDir + BASE_DATA_PACKAGE_VIOLATION_MANAGE;
        new File(violationManagePath).getParentFile().mkdirs();
        // 1.生成“ViolationManage.xml“文件
        XmlUtil.toXmlFile(violationManage, violationManagePath);

        ArrayList<String> fileList = new ArrayList<>();
        fileList.add(violationManagePath);
        File breakRuleFile = new File(tempDir + BASE_DATA_PACKAGE_BREAK_RULE);
        // 2.把第一步生成的xml文件打包，生成“违纪处理办法.zip”文件
        ZipUtil.zipFiles(fileList, breakRuleFile.getAbsolutePath());
        return breakRuleFile;
    }

    /**
     * 校验是否可以生成基础包
     *
     * @param task
     */
    private void check(Task task) {
        if (task == null) {
            throw new KqException(ResponseCode.GENERATE_BASE_DATA_PACKAGE_TASK_NOT_EXIST.getCode(),
                    ResponseCode.GENERATE_BASE_DATA_PACKAGE_TASK_NOT_EXIST.getMsg());
        }
        // 判断是否锁定编排
        iTaskService.isLockDataThrowException(task.getId());
    }

    @Override
    public void deleteBaseDataPackageByTaskId(String taskId) {
        // 校验任务数据锁定状态(后续版本考虑优化为从缓存中获取状态)
        iTaskService.isLockDataThrowException(taskId);
        baseDataPackageMapper.delete(Wrappers.<BaseDataPackage>lambdaQuery().eq(BaseDataPackage::getTaskId, taskId));
    }

    @Override
    public String getBaseDataPackageUrl(String taskId) {
        return baseDataPackageMapper.getBaseDataPackageUrl(taskId);
    }

    @Override
    public BaseDataPackageVO queryBaseDataPackage(String taskId) {
        return baseDataPackageMapper.queryBaseDataPackage(taskId);
    }

    @Override
    public void copyBaseDataPackage(String newTaskId, String oldTaskId) {
        baseDataPackageMapper.copyBaseDataPackage(newTaskId, oldTaskId);
    }

    @Override
    public BaseDataPackage getBaseDataPackageByTaskCode(String taskCode) {
        return baseDataPackageMapper.getBaseDataPackageByTaskCode(taskCode);
    }

}
